// Copyright (C) 2010 Razvan Constantin <razvan.constantin@rconst.net>
//
// This file is part of FileBow.
//
// FileBow is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// FileBow is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with FileBow.  If not, see <http://www.gnu.org/licenses/>.

// Implementation of NavigateDlg class.

#include "ui/navigate-dlg.h"

#include <string>
#include <vector>

#include <gdk/gdkkeysyms.h>
#include <Poco/Path.h>

#include "common/common.h"
#include "logic/navigator.h"
#include "ui/geany-bridge.h"

using namespace std;
using Poco::Path;

namespace filebow {

extern "C" void NavigateDlg_OnFilterChange(GtkWidget* entry, NavigateDlg* dlg) {
  dlg->Update();
}

extern "C" void NavigateDlg_OnRescan(GtkButton* button, NavigateDlg* dlg) {
  dlg->Rescan();
}

extern "C" void NavigateDlg_OnTreeRowActivated(GtkTreeView* tree_view,
    GtkTreePath* path, GtkTreeViewColumn* column, GtkDialog* dialog) {
  gtk_dialog_response(dialog, GTK_RESPONSE_OK);
}

extern "C" void NavigateDlg_OpenFile(GtkTreeModel *model,
    GtkTreePath *path, GtkTreeIter *iter, gpointer data) {
  GValue value = {0, };
  gtk_tree_model_get_value(model, iter, 0, &value);
  if (G_VALUE_HOLDS_STRING(&value)) {
    #ifndef NAVIGATE_DLG_TEST
    const gchar* project_path = GB_geany_project_base_path();
    Path filePath(project_path ? project_path : "/");
    filePath.makeDirectory();
    filePath.resolve(Path(g_value_get_string(&value)));
    GB_document_open_file(filePath.toString().c_str(), false);
    #endif
  }
  g_value_unset(&value);
}

NavigateDlg::NavigateDlg(Navigator* navigator) {
  mNavigator = navigator;
  InitTreeStore();
  InitTree();
  InitDialog();
}

NavigateDlg::~NavigateDlg() {
  gtk_widget_destroy(GTK_WIDGET(dialog));
}

void NavigateDlg::Show() {
  UpdateTreeStore();
  if (gtk_dialog_run(dialog) != GTK_RESPONSE_OK) {
    return;
  }
  GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
  gtk_tree_selection_selected_foreach(selection, NavigateDlg_OpenFile, NULL);
}

void NavigateDlg::InitTreeStore() {
  treeStore = gtk_list_store_new(1, G_TYPE_STRING);
}

void NavigateDlg::InitTree() {
  tree = gtk_tree_view_new();
  gtk_tree_view_set_model(GTK_TREE_VIEW(tree), GTK_TREE_MODEL(treeStore));
  // Renderer.
  gtk_widget_set_size_request(tree, 800, 500);
  GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
  gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(tree),
      -1, "File", renderer, "text", 0, NULL);
}

void NavigateDlg::InitDialog() {
  dialog = GTK_DIALOG(gtk_dialog_new());
  gtk_window_set_title(GTK_WINDOW(dialog), "File Navigator");
  gtk_dialog_set_has_separator(dialog, TRUE);
  gtk_dialog_add_button(dialog, "Open", GTK_RESPONSE_OK);
  gtk_dialog_set_default_response(dialog, GTK_RESPONSE_OK);
  // Filter input
  GtkWidget* hbox = gtk_hbox_new(FALSE, 10);
  GtkWidget* label = gtk_label_new("Filter");
  filter = gtk_entry_new();
  g_signal_connect(filter, "changed", G_CALLBACK(NavigateDlg_OnFilterChange), this);
  gtk_entry_set_activates_default(GTK_ENTRY(filter), TRUE);
  gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 8);
  gtk_box_pack_start(GTK_BOX(hbox), filter, TRUE, TRUE, 8);
  // Rescan button
  GtkWidget* rescan = gtk_button_new_with_label("Rescan");
  g_signal_connect(rescan, "clicked", G_CALLBACK(NavigateDlg_OnRescan), this);
  gtk_box_pack_start(GTK_BOX(hbox), rescan, TRUE, TRUE, 8);
  gtk_box_pack_start(GTK_BOX(dialog->vbox), hbox, TRUE, TRUE, 8);
  // Tree
  GtkWidget* swindow = gtk_scrolled_window_new(
      gtk_tree_view_get_hadjustment(GTK_TREE_VIEW(tree)),
      gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(tree)));
  gtk_container_add(GTK_CONTAINER(swindow), tree);
  gtk_box_pack_start(GTK_BOX(dialog->vbox), swindow, TRUE, TRUE, 8);
  g_signal_connect(tree, "row-activated", G_CALLBACK(NavigateDlg_OnTreeRowActivated), dialog);
  // Make visible
  gtk_widget_show_all(GTK_WIDGET(dialog));
}

void NavigateDlg::Update() {
  UpdateTreeStore();
}

void NavigateDlg::Rescan() {
  mNavigator->Rescan();
  mNavigator->WaitScan();
  Update();
}

void NavigateDlg::UpdateTreeStore() {
  // Update file list from navigator.
  vector<string> files;
  mNavigator->BuildTop(gtk_entry_get_text(GTK_ENTRY(filter)), 50, &files);
  // Update tree content.
  gtk_list_store_clear(treeStore);
  for (int i = 0; i < files.size(); ++i) {
    GtkTreeIter it;
    gtk_list_store_append(treeStore, &it);
    gtk_list_store_set(treeStore, &it, 0, files[i].c_str(), -1);
  }
  // Select first file.
  GtkTreePath* root = gtk_tree_path_new_first();
  gtk_tree_selection_select_path(
      gtk_tree_view_get_selection(GTK_TREE_VIEW(tree)),
      root);
  gtk_tree_path_free(root);
}

} // namespace filebow;
